package simulationhandlers;

import forces.Force;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import physicalobjects.Mass;
import physicalobjects.Spring;


/**
 * Creates an Assembly, which holds physical objects and forces.
 *
 * @author Kathleen Lan, Seon Kang
 */

public class Assembly {

    private ArrayList<Mass> myMasses;
    private ArrayList<Spring> mySprings;
    private ArrayList<Force> myForces;
    private Mass myClosestMassToMousePosition;

    /**
     * 
     */
    public Assembly () {
        myMasses = new ArrayList<Mass>();
        mySprings = new ArrayList<Spring>();
        myForces = new ArrayList<Force>();
    }

    /**
     *
     * @param m 
     */
    public void add (Mass m) {
        myMasses.add(m);
        m.setAssembly(this);
    }

    /**
     * 
     * @param s 
     */
    public void add (Spring s) {
        mySprings.add(s);
    }

    /**
     * 
     * @param f 
     */
    public void add (Force f) {
        myForces.add(f);
    }

    /**
     * 
     */
    public void clearForces() {
        myForces.clear();
    }
    /**
     * This duplicated code can't be reduced because PhysicalObject is an interface
     * 
     * @param pen 
     */
    public void paint (Graphics2D pen) {
        for (Mass m : myMasses) {
            m.paint(pen);
        }
        for (Spring s : mySprings) {
            s.paint(pen);
        }
    }
    /**
     * @param canvas 
     * @param dt 
     * @param boundSizeChange 
     */
    public void update (Simulation canvas, double dt, int boundSizeChange) {
        updateSprings(canvas, dt);
        updateMasses(canvas, dt);
    }
    /**
     * 
     * update all the forces for each mass.
     * 
     * @param canvas 
     * @param dt 
     */
    public void updateMasses (Simulation canvas, double dt) { 
        for (Mass m : myMasses) {
            for (Force f : myForces) {
                f.update(m);
            }
            m.update(canvas, dt);
        }
    }

    /**
     * 
     * @param forceName 
     */
    public void toggleForce (String forceName) {
        for (Force f : myForces) {
            if ((f.getName()).equals(forceName)) {
                f.toggleForce();
            }
        }
    }

    /**
     * @param canvas 
     * @param dt 
     */
    public void updateSprings (Simulation canvas, double dt) {
        for (Spring s : mySprings) {
            s.update(canvas, dt);
        }
    }

    /**
     * @param n 
     */
    public void updateBoundSize (int n) {
        for (Mass m : myMasses) {
            m.updateBoundSizeChange(n);
        }
    }

    /**
     * @param myID 
     * @return
     */
    public Mass getMass (int myID) {
        for (Mass m : myMasses) {
            if (m.match(myID)) {
                return m;
            }
        }
        return null;
    }

    /**
     * @param p 
     * @return
     */
    public double findClosestMass (Point p) {
        myClosestMassToMousePosition = myMasses.get(0);
        double shortestDistance = p.distance(myClosestMassToMousePosition.getCenter());
        for (Mass m : myMasses) {
            if (p.distance(m.getCenter()) < shortestDistance) {
                shortestDistance = p.distance(m.getCenter());
                myClosestMassToMousePosition = m;
            }
        }
        return shortestDistance;
    }

    /**
     * @return
     */
    public Mass getClosestMass () {
        return myClosestMassToMousePosition;
    }

    /**
     * @return
     */
    public Point2D calculateCenterOfMass () {
     // stores sum of x-position of all Masses weighted
        // according to the mass of the Mass
        int sumX = 0;
     // stores sum of y-position of all Masses weighted
        // according to the mass of the Mass
        int sumY = 0;
     // stores sum of all of the masses of the Masses
        int sumMasses = 0;
        Point2D currentMassPosition;
        for (Mass m : myMasses) {
            if (m.getMass() > 0) {
                currentMassPosition = m.getCenter();
                sumX += m.getMass() * currentMassPosition.getX();
                sumY += m.getMass() * currentMassPosition.getY();
                sumMasses += m.getMass();
            }
        }

        Point2D p = new Point(sumX / sumMasses, sumY / sumMasses);
        return p;
    }

}
